package org.dei.perla.sys.device.channel.frame.receiver;

import org.dei.perla.sys.device.channel.frame.FrameConfiguration;

/**
 * Ricevitore di un pacchetto headerless
 *
 */
public class FrameReceiverHeaderLess extends FrameReceiver {

	/**
	 * Stati del ricevitore headerless
	 * 
	 */
	private enum State {

		// Stato di attesa del byte delimitatore di inizio frame
		Start,

		// Stato di ricezione payload
		ReceivingPayload,

		// Stato di riconoscimento di una sequenza di escape 
		Escaping
	};

	/**
	 * Stato corrente del ricevitore
	 */
	private State pState;

	/**
	 * Inizializza il ricevitore di frame headerless
	 * @param parConfiguration Configurazione frame
	 * @param parEvents Gestore eventi di ricezione
	 */
	public FrameReceiverHeaderLess(FrameConfiguration parConfiguration) {
		
		super(parConfiguration);

		// Inizializza lo stato del ricevitore
		this.pState = State.Start;
	}

	@Override
	protected void pNotifyFrame() {

		byte[] tBuffer;

		// Copia il frame ricevuto in un nuovo vettore 
		if (this.pBufferCount > 0)
			tBuffer = java.util.Arrays.copyOfRange(this.pBuffer, 0,
					this.pBufferCount);
		else
			tBuffer = new byte[0];

		// Invia l'evento
		this.pEvents.onFrameReceivedHeaderLess(tBuffer);
	}

	@Override
	public void reset() {
		this.pState = State.Start;
		this.pBufferReset();
	}

	@Override
	public void receiveByte(byte parReceivedByte) {
		
		// Ricevo il payload
		if (this.pState == State.ReceivingPayload) {

			// Ricevuto byte di escape
			if (parReceivedByte == this.pConfiguration.getByteEscape()) {
				this.pState = State.Escaping;
			}
			
			// Ricevuto terminatore
			else if (parReceivedByte == this.pConfiguration.getByteDelimiterEnd()) {
				this.pNotifyFrame();
				this.reset();
			}
			
			// Ricevuto un delimitatore d'inizio frame
			else if (parReceivedByte == this.pConfiguration.getByteDelimiterStartHeaderLess()) {
				this.pNotifyUnclosedFrame();
				this.reset();
			}
			
			// Ricevuto un byte valido
			else {
				this.pBufferAppend(parReceivedByte);
			}
		
		}
			
		// Ricevo un byte con escape
		else if (this.pState == State.Escaping) {
			
			this.pBufferAppend(parReceivedByte);
			this.pState = State.ReceivingPayload;
			
		}
				
		// Ricezione delimitatore inizio frame
		else {

			// Ricevuto un delimitatore d'inizio frame
			if (parReceivedByte == this.pConfiguration.getByteDelimiterStartHeaderLess()) {
				this.pState = State.ReceivingPayload;
			}

			// Riceuto altro
			else {
				this.pNotifyInvalidByte(parReceivedByte);
				this.reset();
			}

		}	
	
	}

}
